<template>
	<div
		:class="['app-editor-container', 'app-upload', `app-upload-${name}`]"
		v-on:drop.capture="handleDrop"
	>
		<a-upload
			v-model:fileList="fileList"
			:action="upload_url"
			:method="method"
			:accept="accept"
			:headers="headers"
			:multiple="multiple"
			:maxCount="maxCount"
			:showUploadList="
				showUploadList
					? {
							showPreviewIcon: rowPreview,
							showRemoveIcon: true,
							showDownloadIcon: true,
					  }
					: false
			"
			:list-type="listType"
			:disabled="disabled || readonly"
			:beforeUpload="beforeUpload"
			@preview="handlePreview"
			@download="DownLoad"
			@change="onChange"
			@click="onClick"
		>
			<template v-if="!maxCount || fileList.length < maxCount">
				<a-button v-if="Object.is(listType, 'text')">
					<UploadOutlined />
					{{ tooltip ? tooltip : $t('common.fileupload.caption', '上传') }}
				</a-button>
				<div v-else>
					<PlusOutlined />
				</div>
			</template>
			<template #downloadIcon>
				<VerticalAlignBottomOutlined />
			</template>
		</a-upload>
		<a-modal
			:visible="previewVisible && rowPreview"
			:title="previewTitle"
			:footer="null"
			@cancel="handleCancel"
		>
			<a-image
				:src="previewFile"
				:fallback="fallback || errorImage"
				:preview="false"
			/>
		</a-modal>
	</div>
</template>

<script setup lang="ts">
import { IEvent, IParam, computedNavData } from '@/core';
import {
	UploadOutlined,
	PlusOutlined,
	VerticalAlignBottomOutlined,
} from '@ant-design/icons-vue';
import { ref, Ref } from 'vue';
import { uploadProps } from './upload';
import {
	getDownloadUrl,
	getRequestingHeader,
	getUploadUrl,
	useEditorTypeParams,
} from '@/hooks/use-editor';
import { Http } from '@/http';
import { Upload } from 'ant-design-vue';

interface EditorEmit {
	(name: 'component-action', value: IEvent<string>): void;
}
const props = defineProps(uploadProps);
const emit = defineEmits<EditorEmit>();
// 类型校验
const {
	validateConfig,
	valueType,
	objectIdField,
	objectValueField,
	objectNameField,
} = useEditorTypeParams();
validateConfig();
const uploadUrl = getUploadUrl(); //文件上传基础路径
const downloadUrl = getDownloadUrl(); //文件下载基础路径
const headers = getRequestingHeader(); //文件请求头
const fileList: Ref<any[]> = ref([]);
const previewVisible = ref(false);
const previewFile = ref('');
const previewTitle = ref('');
let errorImage = ref('');
let upload_url = ref(''); //文件上传最终路径
let upload_params: IParam = reactive({}); //文件上传参数
let export_params: IParam = reactive({}); // 文件下载参数
let localFileList: Ref<any[]> = ref([]);

//初始化
onBeforeMount(() => {
	getParams();
	handleUploadUrlParams();
});

watch(
	() => props.value,
	(newVal: any, oldVal: any) => {
		if (!newVal) {
			fileList.value = [];
			localFileList.value = [];
			return;
		}
		if (Array.isArray(newVal)) {
			fileList.value = newVal.map((item: any, index: any) => {
				if (!item) {
					return;
				}
				return {
					uid: index,
					name: item[objectNameField || 'name'],
					status: 'done',
					fileid: item[objectIdField || 'id'],
					url: downloadUrl + '/' + item[objectIdField || 'id'],
				};
			});
			localFileList.value = newVal;
		} else if (typeof newVal === 'string') {
			const value = JSON.parse(newVal);
			fileList.value = value.map((item: any, index: any) => {
				if (!item) {
					return;
				}
				return {
					uid: index,
					name: item.name,
					status: 'done',
					fileid: item.id,
					url: downloadUrl + '/' + item.id,
				};
			});
			localFileList.value = value;
		} else {
			fileList.value = [
				{
					uid: newVal[objectIdField || 'id'],
					name: newVal[objectNameField || 'name'],
					status: 'done',
					fileid: newVal[objectIdField || 'id'],
					url: downloadUrl + '/' + newVal[objectIdField || 'id'],
				},
			];
			localFileList.value = [newVal];
		}
	},
	{
		deep: true,
		immediate: true,
	}
);

const getParams = () => {
	const { uploadparams, exportparams, viewParams, context } = props;
	const up_params =
		Object.keys(uploadparams).length > 0
			? JSON.parse(JSON.stringify(uploadparams))
			: {};
	const ex_params =
		Object.keys(exportparams).length > 0
			? JSON.parse(JSON.stringify(exportparams))
			: {};
	let _data: any = JSON.parse(JSON.stringify(props.data));

	if (up_params && Object.keys(up_params).length > 0) {
		upload_params = computedNavData(_data, viewParams, context, up_params);
	}
	if (ex_params && Object.keys(ex_params).length > 0) {
		export_params = computedNavData(_data, viewParams, context, ex_params);
	}
};

//处理上传参数
const handleUploadUrlParams = () => {
	upload_url.value = formatUrlParam(uploadUrl, upload_params);
};

//格式化自定义文件参数
const formatUrlParam = (url: string, params: IParam) => {
	const length = Object.keys(params).length;
	if (length > 0) {
		let _url = url + '?';
		Object.keys(params).forEach((item, index) => {
			_url += `${item}=${upload_params[item]}`;
			if (index < length - 1) {
				_url += '&';
			}
		});
		return _url;
	}
	return url;
};

//预览
const handlePreview = async (file: any) => {
	if (props.rowPreview) {
		if (!file.url && !file.preview) {
			file.preview = (await getBase64(file.originFileObj)) as string;
		}
		previewFile.value = file.url || file.preview;
		//当url出现错误且未设置容错资源时，使用Base64之后的文件作为预览资源
		// errorImage.value = (await getBase64(file.originFileObj)) as string;
		previewTitle.value =
			file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
		if (!Object.is(props.listType, 'text')) {
			previewVisible.value = true;
		} else {
			const filetypewarn = App.ts('common.generic.warn', '警告');
			App.getNotificationHelper().warning(
				filetypewarn,
				'暂不支持该类型文件在线预览,请下载后查看'
			);
			previewFile.value = '';
		}
	}
};

//关闭模态
const handleCancel = () => {
	previewVisible.value = false;
	previewTitle.value = '';
};

const onChange = ($event: any) => {
	const status = $event.file.status;
	if (status != 'done' && status != 'removed') {
		return;
	}
	if ($event.file.status == 'done' && $event.file.response) {
		const res = $event.file.response;
		let result: any = { id: res.id, name: res.name };
		if (valueType === 'OBJECT' || valueType === 'OBJECTS') {
			result = {
				[objectIdField || 'id']: res.id,
				[objectNameField || 'name']: res.name,
				[objectValueField || 'value']: res,
			};
		}
		props.multiple
			? localFileList.value.push(result)
			: (localFileList.value = [result]);
	}
	if ($event.file.status == 'removed') {
		const index = localFileList.value.findIndex((item: any) => {
			return item[objectIdField || 'id'] == $event.file.fileid;
		});
		if (index != -1) {
			localFileList.value.splice(index, 1);
		}
	}
	let value: any = JSON.stringify(localFileList.value);
	if (valueType === 'OBJECT') {
		value = localFileList.value.length > 0 ? localFileList.value[0] : null;
	} else if (valueType === 'OBJECTS') {
		value = localFileList.value;
	}
	// 多选时文件为上传完毕 不抛值
	if (
		$event.fileList.some((item: any) => {
			return item.status == 'uploading';
		})
	) {
		return;
	}
	emit('component-action', {
		name: `${props.name}`,
		action: 'valueChange',
		data: value,
	});
};

const getBase64 = (file: File) => {
	return new Promise((resolve, reject) => {
		const reader = new FileReader();
		reader.readAsDataURL(file);
		reader.onload = () => resolve(reader.result);
		reader.onerror = (error) => reject(error);
	});
};

//上传之前
const beforeUpload = (file: any) => {
	const uploaderror = App.ts('common.fileupload.uploaderror', '上传失败');
	// 校验文件大小
	if (props.maxSize > 0 && file.size > props.maxSize * 1000) {
		const filetypeerrorinfo = App.ts(
			'common.fileupload.fileoutofsize' + +props.maxSize + 'kb',
			'超出最大文件大小，最大值为：' + props.maxSize + 'kb'
		);
		App.getNotificationHelper().warning(uploaderror, filetypeerrorinfo);
		return Upload.LIST_IGNORE;
	}
	// 校验文件类型
	if (!validateFileType(file.name)) {
		const filetypeerrorinfo = App.ts(
			'common.fileupload.filetypeerrorpleaseselect' +
				props.fileTypes?.toString(),
			'文件类型错误，请选择: ' + props.fileTypes?.toString()
		);
		App.getNotificationHelper().warning(uploaderror, filetypeerrorinfo);
		return Upload.LIST_IGNORE;
	}
	if (props.imageOnly) {
		const imageTypes = ['image/jpeg', 'image/gif', 'image/png', 'image/bmp'];
		const isImage = imageTypes.some((type: any) => Object.is(type, file.type));
		if (!isImage) {
			const filetypeerrorinfo = App.ts(
				'common.fileupload.filetypeerrorinfo',
				'请上传图片类型的文件'
			);
			App.getNotificationHelper().warning(uploaderror, filetypeerrorinfo);
			return Upload.LIST_IGNORE;
		}
	}
	if (props.pdfOnly && !Object.is(file.type, 'application/pdf')) {
		const notpdffiletype = App.ts(
			'common.fileupload.notpdffiletype',
			'文件类型错误，请选择pdf文件类型'
		);
		App.getNotificationHelper().warning(uploaderror, notpdffiletype);
		return Upload.LIST_IGNORE;
	}
	return true;
};

// 根据文件名称校验文件类型
const validateFileType = (fileName: string): boolean => {
	if (!props.fileTypes || props.fileTypes.length == 0) {
		return true;
	}
	const fileNameArray = fileName.split('.');
	if (fileNameArray.length == 0) {
		return false;
	}
	const filetype = fileNameArray[fileNameArray.length - 1];
	return props.fileTypes.findIndex((item) => item == filetype) != -1;
};

//判断是否允许拖拽上传
const handleDrop = (event: any) => {
	if (!props.isdrop && event.type === 'drop') {
		event.stopPropagation();
		event.preventDefault();
		const uploadwarn = App.ts('common.generic.warn', '警告');
		const draguploaderror = App.ts(
			'common.fileupload.draguploaderror',
			'不允许拖拽上传'
		);
		App.getNotificationHelper().warning(uploadwarn, draguploaderror);
		return false;
	}
};

//下载文件
const DownLoad = (file: any) => {
	DownloadFile(file.url, file);
};
//下载文件
const DownloadFile = (url: string, file: any) => {
	const baseUrl = import.meta.env.VITE_BASE_URL;
	const index = url.indexOf(baseUrl);
	if (index != -1) {
		url = url.replace(baseUrl, '');
	}
	// 发送get请求
	const downloaderror = App.ts('common.fileupload.downloaderror', '下载失败');
	Http.getHttp()({
		method: App.getProjectSetting().appRequestMode,
		url: url,
		responseType: 'blob',
	})
		.then((response: any) => {
			if (!response || response.status != 200) {
				App.getNotificationHelper().error(
					App.ts('common.generic.error', '错误'),
					downloaderror
				);
				return;
			}
			// 请求成功，后台返回的是一个文件流
			if (response.data) {
				// 获取文件名
				const filename = file.name;
				const ext = '.' + filename.split('.').pop();
				let filetype = calcFilemime(ext);
				// 用blob对象获取文件流
				let blob = new Blob([response.data], { type: filetype });
				// 通过文件流创建下载链接
				var href = URL.createObjectURL(blob);
				// 创建一个a元素并设置相关属性
				let a = document.createElement('a');
				a.href = href;
				a.download = filename;
				// 添加a元素到当前网页
				document.body.appendChild(a);
				// 触发a元素的点击事件，实现下载
				a.click();
				// 从当前网页移除a元素
				document.body.removeChild(a);
				// 释放blob对象
				URL.revokeObjectURL(href);
			} else {
				App.getNotificationHelper().error(
					App.ts('common.generic.error', '错误'),
					downloaderror
				);
			}
		})
		.catch((error: any) => {
			App.getNotificationHelper().error(
				App.ts('common.generic.error', '错误'),
				error && error.message ? error.message : `文件${downloaderror}`
			);
		});
};
//计算文件类型
const calcFilemime = (filetype: string): string => {
	let mime = 'image/png';
	switch (filetype) {
		case '.wps':
			mime = 'application/kswps';
			break;
		case '.doc':
			mime = 'application/msword';
			break;
		case '.docx':
			mime =
				'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
			break;
		case '.txt':
			mime = 'text/plain';
			break;
		case '.zip':
			mime = 'application/zip';
			break;
		case '.png':
			mime = 'imgage/png';
			break;
		case '.gif':
			mime = 'image/gif';
			break;
		case '.jpeg':
			mime = 'image/jpeg';
			break;
		case '.jpg':
			mime = 'image/jpeg';
			break;
		case '.rtf':
			mime = 'application/rtf';
			break;
		case '.avi':
			mime = 'video/x-msvideo';
			break;
		case '.gz':
			mime = 'application/x-gzip';
			break;
		case '.tar':
			mime = 'application/x-tar';
			break;
	}
	return mime;
};

/**
 * 点击
 * @param $event
 * @remember AppUpload
 */
const onClick = ($event: any) => {
	emit('component-action', {
		name: `${props.name}`,
		action: 'editorClick',
		data: $event,
	});
};
</script>
